from typing import Union
from aioredis import Redis
from fastapi import APIRouter, Depends, Request
from fast_captcha import img_captcha
from starlette.responses import StreamingResponse
from loguru import logger
from config import settings
from dependencies import get_redis, create_access_token, get_captcha_code, get_current_active_user

from enums import OperationMethod as OpMethod, OperationObject as OpObject
from models import OperationLog, User
from schemas import (
    FailResp,
    LoginResult,
    ModifyInfo,
    ModifyPassword,
    RoleInfoForLoginResp,
    SingleResp,
    SuccessResp,
    UserInfo,
    UserLogin,
    UserRegister,
)

router = APIRouter(prefix="/user", tags=["用户中心"])


@router.get("/captcha", summary="图片验证码")
async def image_captcha(req: Request, redis: Redis = Depends(get_redis)):
    image, text = img_captcha()  # 默认 img_byte='bytesio','file', 'base64'
    logger.success(f"验证码: {text}")
    session_value = req.session.get(settings.session_cookie_name)  # 7dd6d0a6c5b961a49145d5bd79433c8f
    key = settings.captcha_key.format(session_value)  # "captcha:{}".format(session_value)
    await redis.setex(key, settings.captcha_seconds, text.lower())
    return StreamingResponse(content=image, media_type="image/jpeg")


@router.post("/login", response_model=Union[SingleResp[LoginResult], FailResp], summary="用户登陆")
async def login(req: Request, post: UserLogin, code_in_redis: str = Depends(get_captcha_code)):
    if code_in_redis is None:
        return FailResp(code=10302, msg="验证码已过期")
    if post.code.lower() != code_in_redis:
        return FailResp(code=10303, msg="验证码错误")
    user = await User.get_or_none(username=post.username)
    if user is None:
        return FailResp(code=10301, msg="账号与密码不匹配")
    if not user.check_password(post.password):
        return FailResp(code=10301, msg="账号与密码不匹配")
    access_token = create_access_token(data={"sub": user.username})

    await OperationLog.add_log(req, user.pk, OpObject.user, OpMethod.login_by_account, f"用户登陆(ID={user.pk})")
    # 此处只是为了配合前端，返回的信息为是否为管理员，没什么实际用处，只是不想改前端代码而已
    role_name = "超级管理员" if user.is_superuser else "普通管理员"
    role_value = "超级管理员" if user.is_superuser else "普通管理员"
    role_info = RoleInfoForLoginResp(role_name=role_name, value=role_value)
    login_result = LoginResult(id=user.pk, token=access_token, role=role_info)

    return SingleResp[LoginResult](data=login_result)


@router.post("", response_model=Union[SingleResp[UserInfo], FailResp], summary="用户注册")
async def register(post: UserRegister, code_in_redis: str = Depends(get_captcha_code)):
    if code_in_redis is None:
        return FailResp(code=10302, msg="验证码已过期")
    if post.code.lower() != code_in_redis:
        return FailResp(code=10303, msg="验证码错误")

    if await User.filter(username=post.username).exists():
        return FailResp(code=10101, msg="当前用户名已被占用")
    user = await User.create(**post.model_dump())
    await user.set_password(post.password)
    user_info = UserInfo.model_validate(user)
    return SingleResp[UserInfo](data=user_info)


@router.get("", response_model=Union[SingleResp[UserInfo], FailResp], summary="查看个人信息")
async def get_my_info(me: User =Depends(get_current_active_user)):
    return SingleResp[UserInfo](data=me)


@router.put("/password", response_model=Union[SuccessResp, FailResp], summary="更改密码")
async def change_password(post: ModifyPassword, me: User = Depends(get_current_active_user)):
    if not me.check_password(post.old_password):
        return FailResp(code=10401, msg="旧密码输入错误")
    await me.set_password(post.new_password)
    return SuccessResp(data="密码更改成功")


@router.put("", response_model=Union[SingleResp[UserInfo], FailResp], summary="修改个人信息")
async def change_info(req: Request, post: ModifyInfo, me: User = Depends(get_current_active_user)):
    await me.update_from_dict(post.model_dump(exclude_unset=True, exclude_none=True))  # dict已弃用,改用model_dump
    await me.save()
    await OperationLog.add_log(req, me.pk, OpObject.user, OpMethod.update_object, f"用户修改个人信息({me.pk})")
    user_info = UserInfo.model_validate(me)  # from_orm 已弃用，改用 model_validate
    return SingleResp[UserInfo](data=user_info)
